package com.ryx.shiro;

import com.alibaba.fastjson.JSON;
import com.ryx.constants.Constant;
import com.ryx.exception.GlobalException;
import com.ryx.exception.code.BaseResponseCode;
import com.ryx.utils.DataResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 * @BelongsPackage: com.ryx.shiro
 * @Author: 容永轩
 * @CreateTime: 2020-11-08
 * @Description:
 */


// /**
//     * 是否允许访问
//     * true：允许，交下一个Filter处理
//     * false：回往下执行onAccessDenied
@Slf4j
public class CustomAccessControFilter extends AccessControlFilter {



    /**
     * 表示访问拒绝时是否自己处理，
     * 如果返回true表示自己不处理且继续拦截器链执行，
     * 返回false表示自己已经处理了（比如直接响应回前端）。
     * @param servletRequest
     * @param servletResponse
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        /**
         * 如果返回true 就会流转到下一个链式调用
         * 如果返回false 就会流转到onAccessDenied方法调用
         */
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        /**
         * 如果返回true 就会流转到下一个链式调用
         * 如果返回false 就会响应前端 不会流转到下一个链式调用
         */
        HttpServletRequest request= (HttpServletRequest) servletRequest;
        log.info("request 接口地址：{}",request.getRequestURI());
        log.info("request 接口的请求方式{}",request.getMethod());
        String accessToken=request.getHeader(Constant.ACCESS_TOKEN);
        try {
            if(StringUtils.isEmpty(accessToken)){
                throw new GlobalException(BaseResponseCode.TOKEN_NOT_NULL);
            }
            CustomUsernamePasswordToken customUsernamePasswordToken=new CustomUsernamePasswordToken(accessToken);

            getSubject(servletRequest,servletResponse).login(customUsernamePasswordToken);
        }catch (GlobalException e){
            customResponse(servletResponse,e.getCode(),e.getMsg());
            return false;
        } catch (AuthenticationException e) {
            if(e.getCause() instanceof GlobalException){
                GlobalException exception= (GlobalException) e.getCause();
                customResponse(servletResponse,exception.getCode(),exception.getMsg());
            }else {
                customResponse(servletResponse,BaseResponseCode.TOKEN_ERROR.getCode(),BaseResponseCode.TOKEN_ERROR.getMsg());
            }
            return false;
        }catch (Exception e){
            customResponse(servletResponse,BaseResponseCode.SYSTEM_ERROR.getCode(),BaseResponseCode.SYSTEM_ERROR.getMsg());
            return false;
        }
        return true;
    }

    //自定义响应前端方法
    private void customResponse(ServletResponse response, int code, String msg) {
        try {
            DataResult result = DataResult.getResult(code, msg);

            response.setContentType(MediaType.APPLICATION_JSON_VALUE);  //"application/json"
            response.setCharacterEncoding("UTF-8");
            String str = JSON.toJSONString(result);
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(str.getBytes(StandardCharsets.UTF_8));
            outputStream.flush();
        } catch (IOException e) {
//            e.printStackTrace();
            log.error("customResponse...error:{}", e.getMessage());
        }


    }

}
